using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using Engine;
using GameEntitySystem;
using LiteNetLib;
using LiteNetLib.Utils;
using TemplatesDatabase;
using XmlUtilities;

namespace Game
{
	public class SubsystemRemotePlayers : Subsystem, IUpdateable
	{
		private class AddPlayerPacket
		{
			[CompilerGenerated]
			private string _003CPlayerData_003Ek__BackingField;

			public string PlayerData
			{
				[CompilerGenerated]
				get
				{
					return _003CPlayerData_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CPlayerData_003Ek__BackingField = value;
				}
			}
		}

		private class RemovePlayerPacket
		{
			[CompilerGenerated]
			private int _003CPlayerIndex_003Ek__BackingField;

			public int PlayerIndex
			{
				[CompilerGenerated]
				get
				{
					return _003CPlayerIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CPlayerIndex_003Ek__BackingField = value;
				}
			}
		}

		private class PlayerInputPacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private RemotePlayerInput _003CInput_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public RemotePlayerInput Input
			{
				[CompilerGenerated]
				get
				{
					return _003CInput_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CInput_003Ek__BackingField = value;
				}
			}
		}

		private enum InventoryChangeType : byte
		{
			set_ActiveSlotIndex,
			AddSlotItems,
			DropAllItems,
			ProcessSlotItems,
			RemoveSlotItems
		}

		private class InventoryChangePacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private InventoryChangeData _003CChange_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public InventoryChangeData Change
			{
				[CompilerGenerated]
				get
				{
					return _003CChange_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CChange_003Ek__BackingField = value;
				}
			}
		}

		private class InventoryChangeData : INetSerializable
		{
			public InventoryChangeType ChangeType;

			public object[] Arguments;

			public void Record(InventoryChangeType type, params object[] args)
			{
				ChangeType = type;
				Arguments = args;
			}

			public void Invoke(IInventory inv)
			{
				switch (ChangeType)
				{
				case InventoryChangeType.set_ActiveSlotIndex:
					inv.ActiveSlotIndex = (int)Arguments[0];
					break;
				case InventoryChangeType.AddSlotItems:
					inv.AddSlotItems((int)Arguments[0], (int)Arguments[1], (int)Arguments[2]);
					break;
				case InventoryChangeType.DropAllItems:
					inv.DropAllItems((Vector3)Arguments[0]);
					break;
				case InventoryChangeType.ProcessSlotItems:
				{
					int num = default(int);
					int num2 = default(int);
					inv.ProcessSlotItems((int)Arguments[0], (int)Arguments[1], (int)Arguments[2], (int)Arguments[3], ref num, ref num2);
					break;
				}
				case InventoryChangeType.RemoveSlotItems:
					inv.RemoveSlotItems((int)Arguments[0], (int)Arguments[1]);
					break;
				}
			}

			public void Deserialize(NetDataReader reader)
			{
				ChangeType = (InventoryChangeType)reader.GetByte();
				switch (ChangeType)
				{
				case InventoryChangeType.set_ActiveSlotIndex:
					Arguments = new object[1] { reader.GetInt() };
					break;
				case InventoryChangeType.AddSlotItems:
					Arguments = new object[3]
					{
						reader.GetInt(),
						reader.GetInt(),
						reader.GetInt()
					};
					break;
				case InventoryChangeType.DropAllItems:
					Arguments = new object[1]
					{
						new Vector3(reader.GetFloat(), reader.GetFloat(), reader.GetFloat())
					};
					break;
				case InventoryChangeType.ProcessSlotItems:
					Arguments = new object[4]
					{
						reader.GetInt(),
						reader.GetInt(),
						reader.GetInt(),
						reader.GetInt()
					};
					break;
				case InventoryChangeType.RemoveSlotItems:
					Arguments = new object[2]
					{
						reader.GetInt(),
						reader.GetInt()
					};
					break;
				}
			}

			public void Serialize(NetDataWriter writer)
			{
				writer.Put((byte)ChangeType);
				switch (ChangeType)
				{
				case InventoryChangeType.set_ActiveSlotIndex:
				case InventoryChangeType.AddSlotItems:
				case InventoryChangeType.ProcessSlotItems:
				case InventoryChangeType.RemoveSlotItems:
				{
					object[] arguments = Arguments;
					foreach (object obj in arguments)
					{
						writer.Put((int)obj);
					}
					break;
				}
				case InventoryChangeType.DropAllItems:
				{
					Vector3 vector = (Vector3)Arguments[0];
					writer.Put(vector.X);
					writer.Put(vector.Y);
					writer.Put(vector.Z);
					break;
				}
				}
			}
		}

		private class InventoryListener : IInventoryListener
		{
			public readonly Queue<InventoryChangeData> ProducedPackets = new Queue<InventoryChangeData>();

			public void SetActiveSlotIndex(int value)
			{
				InventoryChangeData inventoryChangeData = new InventoryChangeData();
				inventoryChangeData.Record(InventoryChangeType.set_ActiveSlotIndex, value);
				ProducedPackets.Enqueue(inventoryChangeData);
			}

			public void AddSlotItems(int slotIndex, int value, int count)
			{
				InventoryChangeData inventoryChangeData = new InventoryChangeData();
				inventoryChangeData.Record(InventoryChangeType.AddSlotItems, slotIndex, value, count);
				ProducedPackets.Enqueue(inventoryChangeData);
			}

			public void DropAllItems(Vector3 position)
			{
				InventoryChangeData inventoryChangeData = new InventoryChangeData();
				inventoryChangeData.Record(InventoryChangeType.DropAllItems, position);
				ProducedPackets.Enqueue(inventoryChangeData);
			}

			public void ProcessSlotItems(int slotIndex, int value, int count, int processCount)
			{
				InventoryChangeData inventoryChangeData = new InventoryChangeData();
				inventoryChangeData.Record(InventoryChangeType.ProcessSlotItems, slotIndex, value, count, processCount);
				ProducedPackets.Enqueue(inventoryChangeData);
			}

			public void RemoveSlotItems(int slotIndex, int count)
			{
				InventoryChangeData inventoryChangeData = new InventoryChangeData();
				inventoryChangeData.Record(InventoryChangeType.RemoveSlotItems, slotIndex, count);
				ProducedPackets.Enqueue(inventoryChangeData);
			}
		}

		private class RemotePlayerData
		{
			public bool IsAlive;

			public Guid PlayerUserId;

			public RemotePlayerInput LatestInput;

			public PlayerSlave PlayerSlave;

			public Queue<InventoryChangeData> inventoryChanges;

			public readonly Queue<InventoryChangeData> pendingInventoryChanges = new Queue<InventoryChangeData>();

			public ComponentPlayer Player
			{
				get
				{
					return PlayerSlave.Player;
				}
			}

			public RemotePlayerData(Guid userId)
			{
				PlayerUserId = userId;
			}

			public void ApplyInventoryChanges()
			{
				while (pendingInventoryChanges.Count > 0)
				{
					pendingInventoryChanges.Dequeue().Invoke(PlayerSlave.OriginalInventory);
				}
			}
		}

		public class PlayerDigPacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private TerrainRaycastResult _003CRaycastResult_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public TerrainRaycastResult RaycastResult
			{
				[CompilerGenerated]
				get
				{
					return _003CRaycastResult_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CRaycastResult_003Ek__BackingField = value;
				}
			}
		}

		public class PlayerHitPacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private int _003CBodyEntityIndex_003Ek__BackingField;

			[CompilerGenerated]
			private Vector3 _003CDirection_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public int BodyEntityIndex
			{
				[CompilerGenerated]
				get
				{
					return _003CBodyEntityIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CBodyEntityIndex_003Ek__BackingField = value;
				}
			}

			public Vector3 Direction
			{
				[CompilerGenerated]
				get
				{
					return _003CDirection_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CDirection_003Ek__BackingField = value;
				}
			}
		}

		public class PlayerInteractPacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private TerrainRaycastResult _003CRaycastResult_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public TerrainRaycastResult RaycastResult
			{
				[CompilerGenerated]
				get
				{
					return _003CRaycastResult_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CRaycastResult_003Ek__BackingField = value;
				}
			}
		}

		public class PlayerPlacePacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private TerrainRaycastResult _003CRaycastResult_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public TerrainRaycastResult RaycastResult
			{
				[CompilerGenerated]
				get
				{
					return _003CRaycastResult_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CRaycastResult_003Ek__BackingField = value;
				}
			}
		}

		public class PlayerUsePacket
		{
			[CompilerGenerated]
			private int _003CIndex_003Ek__BackingField;

			[CompilerGenerated]
			private Vector3 _003CViewPosition_003Ek__BackingField;

			[CompilerGenerated]
			private Vector3 _003CDirection_003Ek__BackingField;

			public int Index
			{
				[CompilerGenerated]
				get
				{
					return _003CIndex_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CIndex_003Ek__BackingField = value;
				}
			}

			public Vector3 ViewPosition
			{
				[CompilerGenerated]
				get
				{
					return _003CViewPosition_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CViewPosition_003Ek__BackingField = value;
				}
			}

			public Vector3 Direction
			{
				[CompilerGenerated]
				get
				{
					return _003CDirection_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CDirection_003Ek__BackingField = value;
				}
			}
		}

		private class PlayerEventSender : IPlayerEventListener
		{
			private SubsystemRemoteEntities entities;

			private int playerIndex;

			public PlayerEventSender(int index, Project project)
			{
				entities = project.FindSubsystem<SubsystemRemoteEntities>();
				playerIndex = index;
			}

			public void OnDig(TerrainRaycastResult result)
			{
				PlayerDigPacket playerDigPacket = new PlayerDigPacket();
				playerDigPacket.Index = playerIndex;
				playerDigPacket.RaycastResult = result;
				NetworkManager.SendPacketToAll(playerDigPacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
			}

			public void OnHit(ComponentBody body, Vector3 direction)
			{
				PlayerHitPacket playerHitPacket = new PlayerHitPacket();
				playerHitPacket.Index = playerIndex;
				playerHitPacket.BodyEntityIndex = entities.GetEntityId(body.Entity);
				playerHitPacket.Direction = direction;
				NetworkManager.SendPacketToAll(playerHitPacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
			}

			public void OnInteract(TerrainRaycastResult result)
			{
				PlayerInteractPacket playerInteractPacket = new PlayerInteractPacket();
				playerInteractPacket.Index = playerIndex;
				playerInteractPacket.RaycastResult = result;
				NetworkManager.SendPacketToAll(playerInteractPacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
			}

			public void OnPlace(TerrainRaycastResult result)
			{
				PlayerPlacePacket playerPlacePacket = new PlayerPlacePacket();
				playerPlacePacket.Index = playerIndex;
				playerPlacePacket.RaycastResult = result;
				NetworkManager.SendPacketToAll(playerPlacePacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
			}

			public void OnUse(Vector3 viewPosition, Vector3 direction)
			{
				PlayerUsePacket playerUsePacket = new PlayerUsePacket();
				playerUsePacket.Index = playerIndex;
				playerUsePacket.ViewPosition = viewPosition;
				playerUsePacket.Direction = direction;
				NetworkManager.SendPacketToAll(playerUsePacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass35_0
		{
			public KeyValuePair<int, RemotePlayerData> pair;

			internal bool _003CFindPlayer_003Eb__0(PlayerData d)
			{
				return d.PlayerIndex == pair.Key;
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass36_0
		{
			public NetPeer peer;

			internal bool _003COnPeerStateChanged_003Eb__1(IPEndPoint p)
			{
				return p != peer.EndPoint;
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class _003C_003Ec
		{
			public static readonly _003C_003Ec _003C_003E9 = new _003C_003Ec();

			public static Func<NetPeer, IPEndPoint> _003C_003E9__36_0;

			internal IPEndPoint _003COnPeerStateChanged_003Eb__36_0(NetPeer p)
			{
				return p.EndPoint;
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass38_0
		{
			public RemovePlayerPacket packet;

			internal bool _003COnRemovePlayer_003Eb__0(PlayerData player)
			{
				return player.PlayerIndex == packet.PlayerIndex;
			}
		}

		[CompilerGenerated]
		private bool _003CHasAuthority_003Ek__BackingField;

		private SubsystemPlayers subsystemPlayers_;

		private SubsystemUpdate subsystemUpdate_;

		private readonly HashSet<int> pendingNewPlayers_ = new HashSet<int>();

		private readonly Dictionary<int, RemotePlayerData> playersData_ = new Dictionary<int, RemotePlayerData>();

		[CompilerGenerated]
		private int _003CMainPlayerCount_003Ek__BackingField;

		public bool HasAuthority
		{
			[CompilerGenerated]
			get
			{
				return _003CHasAuthority_003Ek__BackingField;
			}
			[CompilerGenerated]
			private set
			{
				_003CHasAuthority_003Ek__BackingField = value;
			}
		}

		public int UpdateOrder
		{
			get
			{
				return -20;
			}
		}

		public int MainPlayerCount
		{
			[CompilerGenerated]
			get
			{
				return _003CMainPlayerCount_003Ek__BackingField;
			}
			[CompilerGenerated]
			set
			{
				_003CMainPlayerCount_003Ek__BackingField = value;
			}
		}

		public bool IsMainPlayer(Entity e)
		{
			if (subsystemPlayers_.IsPlayer(e))
			{
				return IsMainPlayer(e.FindComponent<ComponentPlayer>(true).PlayerData);
			}
			return false;
		}

		public bool IsMainPlayer(PlayerData player)
		{
			return playersData_[player.PlayerIndex].PlayerUserId == NetworkManager.ClientId;
		}

		public bool IsNewPlayer(int playerIndex)
		{
			return pendingNewPlayers_.Contains(playerIndex);
		}

		public void Update(float dt)
		{
			foreach (ComponentPlayer componentPlayer in subsystemPlayers_.ComponentPlayers)
			{
				int playerIndex = componentPlayer.PlayerData.PlayerIndex;
				RemotePlayerData remotePlayerData = playersData_[playerIndex];
				if (IsMainPlayer(componentPlayer.PlayerData))
				{
					if (pendingNewPlayers_.Remove(playerIndex))
					{
						XElement node = new XElement("Player");
						ValuesDictionary valuesDictionary = new ValuesDictionary();
						ValuesDictionary valuesDictionary2 = new ValuesDictionary();
						componentPlayer.PlayerData.Save(valuesDictionary2);
						valuesDictionary.SetValue("PlayerData", valuesDictionary2);
						valuesDictionary.SetValue("PlayerIndex", componentPlayer.PlayerData.PlayerIndex);
						valuesDictionary.SetValue("UserId", remotePlayerData.PlayerUserId);
						valuesDictionary.Save(node);
						Log.Information("Sending add player packet");
						AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
						addPlayerPacket.PlayerData = XmlUtils.SaveXmlToString(node, true);
						NetworkManager.SendPacketToAll(addPlayerPacket, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
						continue;
					}
					if (remotePlayerData.PlayerSlave == null)
					{
						Log.Information("creating new player slave");
						InventoryListener inventoryListener = new InventoryListener();
						remotePlayerData.inventoryChanges = inventoryListener.ProducedPackets;
						remotePlayerData.PlayerSlave = new PlayerSlave(base.Project, componentPlayer, new PlayerEventSender(componentPlayer.PlayerData.PlayerIndex, base.Project), inventoryListener);
					}
					try
					{
						remotePlayerData.PlayerSlave.ServerUpdate(dt);
					}
					catch (Exception message)
					{
						Log.Error(message);
					}
					if (Time.PeriodicEvent(0.019999999552965164, dt))
					{
						PlayerInputPacket playerInputPacket = new PlayerInputPacket();
						playerInputPacket.Index = playerIndex;
						playerInputPacket.Input = new RemotePlayerInput(componentPlayer);
						NetworkManager.SendPacketToAll(playerInputPacket, DeliveryMethod.Sequenced, NetworkManager.PeerStage.Ready);
						while (remotePlayerData.inventoryChanges.Count > 0)
						{
							InventoryChangePacket inventoryChangePacket = new InventoryChangePacket();
							inventoryChangePacket.Index = playerIndex;
							inventoryChangePacket.Change = remotePlayerData.inventoryChanges.Dequeue();
							InventoryChangePacket inventoryChangePacket2 = inventoryChangePacket;
							Log.Information("inventory change packet " + inventoryChangePacket2.Change.ChangeType);
							NetworkManager.SendPacketToAll(inventoryChangePacket2, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.Ready);
						}
					}
				}
				else if (remotePlayerData.IsAlive)
				{
					if (remotePlayerData.PlayerSlave == null)
					{
						Log.Information("creating new player slave");
						remotePlayerData.PlayerSlave = new PlayerSlave(base.Project, componentPlayer, null, null);
					}
					remotePlayerData.PlayerSlave.ClientUpdate(dt, playersData_[playerIndex].LatestInput);
					try
					{
						remotePlayerData.ApplyInventoryChanges();
					}
					catch (Exception message2)
					{
						Log.Error(message2);
					}
				}
			}
		}

		protected override void Load(ValuesDictionary valuesDictionary)
		{
			HasAuthority = valuesDictionary.GetValue<bool>("HasAuthority");
			subsystemPlayers_ = base.Project.FindSubsystem<SubsystemPlayers>(true);
			subsystemUpdate_ = base.Project.FindSubsystem<SubsystemUpdate>(true);
			subsystemPlayers_.PlayerAdded += new Action<PlayerData>(_003CLoad_003Eb__32_0);
			subsystemPlayers_.PlayerRemoved += new Action<PlayerData>(_003CLoad_003Eb__32_1);
			NetworkManager.PeerStateChanged += new Action<NetPeer>(OnPeerStateChanged);
			NetworkManager.RegisterStructPacket<RemotePlayerInput>();
			NetworkManager.RegisterStructPacket<Vector3>();
			NetworkManager.RegisterStructPacket<TerrainRaycastResult>();
			NetworkManager.RegisterPacketClass<InventoryChangeData>();
			NetworkManager.SubscribePacket(new Action<PlayerInputPacket, NetPeer>(OnRecivePlayerInput));
			NetworkManager.SubscribeReusablePacket(new Action<AddPlayerPacket, NetPeer>(OnAddPlayer));
			NetworkManager.SubscribeReusablePacket(new Action<RemovePlayerPacket, NetPeer>(OnRemovePlayer));
			NetworkManager.SubscribeReusablePacket(new Action<PlayerDigPacket, NetPeer>(_003CLoad_003Eb__32_2));
			NetworkManager.SubscribeReusablePacket(new Action<PlayerPlacePacket, NetPeer>(_003CLoad_003Eb__32_3));
			NetworkManager.SubscribeReusablePacket(new Action<PlayerInteractPacket, NetPeer>(_003CLoad_003Eb__32_4));
			NetworkManager.SubscribeReusablePacket(new Action<PlayerHitPacket, NetPeer>(_003CLoad_003Eb__32_5));
			NetworkManager.SubscribeReusablePacket(new Action<PlayerUsePacket, NetPeer>(_003CLoad_003Eb__32_6));
			NetworkManager.SubscribePacket(new Action<InventoryChangePacket, NetPeer>(OnReciveInventoryChange));
			ValuesDictionary value = valuesDictionary.GetValue<ValuesDictionary>("PlayerUserIds", null);
			if (value != null)
			{
				foreach (string key in value.Keys)
				{
					playersData_.Add(int.Parse(key), new RemotePlayerData(value.GetValue<Guid>(key)));
				}
			}
			foreach (NetworkManager.PeerData readyPeer in NetworkManager.ReadyPeers)
			{
				foreach (RemotePlayerData value2 in playersData_.Values)
				{
					if (value2.PlayerUserId == readyPeer.UserId)
					{
						value2.IsAlive = true;
					}
				}
			}
		}

		protected override void Save(ValuesDictionary valuesDictionary)
		{
			base.Save(valuesDictionary);
			ValuesDictionary valuesDictionary2 = new ValuesDictionary();
			foreach (KeyValuePair<int, RemotePlayerData> item in playersData_)
			{
				valuesDictionary2[item.Key.ToString()] = item.Value.PlayerUserId;
			}
			valuesDictionary.SetValue("PlayerUserIds", valuesDictionary2);
		}

		public override void Dispose()
		{
			NetworkManager.ClientStage = NetworkManager.PeerStage.NotReady;
			NetworkManager.RemoveSubscribtion<PlayerInputPacket>();
			NetworkManager.RemoveSubscribtion<AddPlayerPacket>();
			NetworkManager.RemoveSubscribtion<RemovePlayerPacket>();
			NetworkManager.RemoveSubscribtion<InventoryChangePacket>();
			NetworkManager.PeerStateChanged -= new Action<NetPeer>(OnPeerStateChanged);
		}

		public PlayerData FindPlayer(Guid userId)
		{
			using (Dictionary<int, RemotePlayerData>.Enumerator enumerator = playersData_.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					_003C_003Ec__DisplayClass35_0 _003C_003Ec__DisplayClass35_ = new _003C_003Ec__DisplayClass35_0();
					_003C_003Ec__DisplayClass35_.pair = enumerator.Current;
					if (_003C_003Ec__DisplayClass35_.pair.Value.PlayerUserId == userId)
					{
						return Enumerable.FirstOrDefault(subsystemPlayers_.PlayersData, new Func<PlayerData, bool>(_003C_003Ec__DisplayClass35_._003CFindPlayer_003Eb__0));
					}
				}
			}
			return null;
		}

		private void OnPeerStateChanged(NetPeer peer)
		{
			_003C_003Ec__DisplayClass36_0 _003C_003Ec__DisplayClass36_ = new _003C_003Ec__DisplayClass36_0();
			_003C_003Ec__DisplayClass36_.peer = peer;
			NetworkManager.PeerData data = NetworkManager.GetData(_003C_003Ec__DisplayClass36_.peer);
			if (data.PeerStage == NetworkManager.PeerStage.Ready)
			{
				PlayerData playerData = FindPlayer(data.UserId);
				if (playerData == null)
				{
					return;
				}
				foreach (ComponentPlayer componentPlayer in subsystemPlayers_.ComponentPlayers)
				{
					if (IsMainPlayer(componentPlayer.PlayerData))
					{
						componentPlayer.ComponentGui.DisplaySmallMessage("Player " + playerData.Name + " has connected", true, true);
					}
				}
				if (NetworkManager.ClientStage == NetworkManager.PeerStage.Ready)
				{
					Log.Information("Player " + playerData.Name + " is now alive");
					playersData_[playerData.PlayerIndex].IsAlive = true;
				}
			}
			else if (data.PeerStage == NetworkManager.PeerStage.DownloadingWorld)
			{
				if (NetworkManager.ClientStage == NetworkManager.PeerStage.Ready && subsystemPlayers_.PlayersData.Count > 0 && HasAuthority)
				{
					Log.Information("Preparing client world");
					LJGameManager.PrepareClientWorld(base.Project);
					using (MemoryStream memoryStream = new MemoryStream())
					{
						LJGameManager.ExportClientWorld(memoryStream);
						WorldFilePacket worldFilePacket = new WorldFilePacket();
						worldFilePacket.Peers = Enumerable.ToArray(Enumerable.Where(Enumerable.Select(NetworkManager.Manager.ConnectedPeerList, _003C_003Ec._003C_003E9__36_0 ?? (_003C_003Ec._003C_003E9__36_0 = new Func<NetPeer, IPEndPoint>(_003C_003Ec._003C_003E9._003COnPeerStateChanged_003Eb__36_0))), new Func<IPEndPoint, bool>(_003C_003Ec__DisplayClass36_._003COnPeerStateChanged_003Eb__1)));
						worldFilePacket.WorldFile = memoryStream.ToArray();
						WorldFilePacket packet = worldFilePacket;
						NetworkManager.SendPacket(_003C_003Ec__DisplayClass36_.peer, packet, DeliveryMethod.ReliableOrdered, NetworkManager.PeerStage.DownloadingWorld);
					}
					List<Entity> list = new List<Entity>();
					foreach (Entity entity in base.Project.Entities)
					{
						if (entity.FindComponent<ComponentPlayer>() == null)
						{
							list.Add(entity);
						}
					}
					base.Project.FindSubsystem<SubsystemRemoteEntities>().SendEntities(_003C_003Ec__DisplayClass36_.peer, list);
				}
				else
				{
					_003C_003Ec__DisplayClass36_.peer.Disconnect();
				}
			}
			else if (data.PeerStage == NetworkManager.PeerStage.Invalid)
			{
				PlayerData playerData2 = FindPlayer(data.UserId);
				if (playerData2 != null)
				{
					Log.Information("Player " + playerData2.Name + " is now not alive");
					playersData_[playerData2.PlayerIndex].IsAlive = false;
				}
				_003C_003Ec__DisplayClass36_.peer.Disconnect();
				if (!HasAuthority)
				{
					GameManager.DisposeProject();
					NetworkManager.ClientStage = NetworkManager.PeerStage.Invalid;
					ScreensManager.SwitchScreen("MainMenu");
					DialogsManager.ShowDialog(null, new MessageDialog("Disconnected from server", "", "OK", null, null));
				}
			}
		}

		private void OnAddPlayer(AddPlayerPacket packet, NetPeer p)
		{
			ValuesDictionary valuesDictionary = new ValuesDictionary();
			valuesDictionary.ApplyOverrides(XmlUtils.LoadXmlFromString(packet.PlayerData, true));
			PlayerData playerData = new PlayerData(base.Project);
			playerData.Load(valuesDictionary.GetValue<ValuesDictionary>("PlayerData"));
			int value = valuesDictionary.GetValue<int>("PlayerIndex");
			playersData_.Add(value, new RemotePlayerData(valuesDictionary.GetValue<Guid>("UserId")));
			subsystemPlayers_.AddPlayerData(playerData);
			if (playerData.PlayerIndex != value && HasAuthority)
			{
				Log.Error(string.Format("Unsynced client at {0}, kicking...", p.EndPoint));
				p.Disconnect();
			}
		}

		private void OnRemovePlayer(RemovePlayerPacket packet, NetPeer p)
		{
			_003C_003Ec__DisplayClass38_0 _003C_003Ec__DisplayClass38_ = new _003C_003Ec__DisplayClass38_0();
			_003C_003Ec__DisplayClass38_.packet = packet;
			subsystemPlayers_.RemovePlayerData(Enumerable.First(subsystemPlayers_.PlayersData, new Func<PlayerData, bool>(_003C_003Ec__DisplayClass38_._003COnRemovePlayer_003Eb__0)));
		}

		private void OnRecivePlayerInput(PlayerInputPacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				playersData_[packet.Index].LatestInput = packet.Input;
			}
			else
			{
				Log.Error("Non-exist player: " + packet.Index);
			}
		}

		private void OnReciveInventoryChange(InventoryChangePacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				playersData_[packet.Index].pendingInventoryChanges.Enqueue(packet.Change);
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_0(PlayerData data)
		{
			if (data.ComponentPlayer == null && !playersData_.ContainsKey(data.PlayerIndex))
			{
				pendingNewPlayers_.Add(data.PlayerIndex);
				playersData_.Add(data.PlayerIndex, new RemotePlayerData(NetworkManager.ClientId));
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_1(PlayerData data)
		{
			playersData_.Remove(data.PlayerIndex);
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_2(PlayerDigPacket packet, NetPeer p)
		{
			Log.Information("Recive dig packet: " + packet.RaycastResult.CellFace.ToString());
			if (playersData_.ContainsKey(packet.Index))
			{
				ComponentMiner componentMiner = playersData_[packet.Index].Player.ComponentMiner;
				SubsystemTerrain subsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>();
				int cellValue = subsystemTerrain.Terrain.GetCellValue(packet.RaycastResult.CellFace.X, packet.RaycastResult.CellFace.Y, packet.RaycastResult.CellFace.Z);
				Block obj = BlocksManager.Blocks[Terrain.ExtractContents(cellValue)];
				Block block = BlocksManager.Blocks[Terrain.ExtractContents(componentMiner.ActiveBlockValue)];
				BlockPlacementData digValue = obj.GetDigValue(subsystemTerrain, componentMiner, cellValue, componentMiner.ActiveBlockValue, packet.RaycastResult);
				subsystemTerrain.DestroyCell(block.ToolLevel, digValue.CellFace.X, digValue.CellFace.Y, digValue.CellFace.Z, digValue.Value, false, false);
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_3(PlayerPlacePacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				playersData_[packet.Index].Player.ComponentMiner.Place(packet.RaycastResult);
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_4(PlayerInteractPacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				playersData_[packet.Index].Player.ComponentMiner.Interact(packet.RaycastResult);
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_5(PlayerHitPacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				Entity entity = GameManager.Project.FindSubsystem<SubsystemRemoteEntities>().GetEntity(packet.BodyEntityIndex);
				if (entity != null)
				{
					playersData_[packet.Index].Player.ComponentMiner.Hit(entity.FindComponent<ComponentBody>(), packet.Direction);
				}
			}
		}

		[CompilerGenerated]
		private void _003CLoad_003Eb__32_6(PlayerUsePacket packet, NetPeer p)
		{
			if (playersData_.ContainsKey(packet.Index))
			{
				playersData_[packet.Index].Player.ComponentMiner.Use(packet.ViewPosition, packet.Direction);
			}
		}
	}
}
